<template>
  <div class="pana-tab__content">
    <a-table
        row-key="index"
        :data-source="listenersList"
        :pagination="false"
        size="small"
        bordered
    >
      <a-table-column
          data-index="index"
          title="序号"
          width="50px"
          :custom-render="(text, record, index) => `${index + 1}`"
      />
      <a-table-column
          data-index="event"
          title="事件类型"
          width="100px"
      />
      <a-table-column
          title="监听器类型"
          width="100px"
          :custom-render="(row) => listenerTypeObject[row.listenerType]"
      />
      <a-table-column
          title="操作"
          width="100px"
      >
        <template slot-scope="text, record, index">
          <a-button
              size="small"
              type="link"
              @click="openListenerForm(record, index)"
          >
            编辑
          </a-button>
          <a-divider type="vertical" />
          <a-button
              size="small"
              type="link"
              style="color: #ff4d4f"
              @click="removeListener(record, index)"
          >
            移除
          </a-button>
        </template>
      </a-table-column>
    </a-table>
    <div class="drawer__button">
      <a-button
          size="small"
          type="primary"
          icon="plus"
          block
          @click="openListenerForm(null)"
      >
        添加监听器
      </a-button>
    </div>

    <!-- 监听器 编辑/创建 部分 -->
    <a-drawer
        :visible="listenerFormModelVisible"
        title="事件监听器"
        :width="`${width}px`"
        @close="listenerFormModelVisible = false"
    >
      <a-form-model
          ref="listenerFormRef"
          :model="listenerForm"
          :label-col="{ span: 6 }"
          :wrapper-col="{ span: 18 }"
      >
        <a-form-model-item
            label="事件类型"
            prop="event"
            :rules="{ required: true, trigger: ['blur', 'change'] }"
        >
          <a-select v-model="listenerForm.event">
            <a-select-option value="start">
              start
            </a-select-option>
            <a-select-option value="end">
              end
            </a-select-option>
          </a-select>
        </a-form-model-item>
        <a-form-model-item
            label="监听器类型"
            prop="listenerType"
            :rules="{ required: true, trigger: ['blur', 'change'] }"
        >
          <a-select v-model="listenerForm.listenerType">
            <a-select-option
                v-for="(value, key, index) in listenerTypeObject"
                :key="key"
                :value="key"
            >
              {{ value }}
            </a-select-option>
          </a-select>
        </a-form-model-item>
        <a-form-model-item
            v-if="listenerForm.listenerType === 'classListener'"
            key="listener-class"
            label="Java类"
            prop="class"
            :rules="{ required: true, trigger: ['blur', 'change'] }"
        >
          <a-input
              v-model="listenerForm.class"
              allow-clear
          />
        </a-form-model-item>
        <a-form-model-item
            v-if="listenerForm.listenerType === 'expressionListener'"
            key="listener-expression"
            label="表达式"
            prop="expression"
            :rules="{ required: true, trigger: ['blur', 'change'] }"
        >
          <a-input
              v-model="listenerForm.expression"
              allow-clear
          />
        </a-form-model-item>
        <a-form-model-item
            v-if="listenerForm.listenerType === 'delegateExpressionListener'"
            key="listener-delegate"
            label="代理表达式"
            prop="delegateExpression"
            :rules="{ required: true, trigger: ['blur', 'change'] }"
        >
          <a-input
              v-model="listenerForm.delegateExpression"
              allow-clear
          />
        </a-form-model-item>
        <template v-if="listenerForm.listenerType === 'scriptListener'">
          <a-form-model-item
              key="listener-script-format"
              label="脚本格式"
              prop="scriptFormat"
              :rules="{
                required: true,
                trigger: ['blur', 'change'],
                message: '请填写脚本格式',
              }"
          >
            <a-input
                v-model="listenerForm.scriptFormat"
                allow-clear
            />
          </a-form-model-item>
          <a-form-model-item
              key="listener-script-type"
              label="脚本类型"
              prop="scriptType"
              :rules="{
                required: true,
                trigger: ['blur', 'change'],
                message: '请选择脚本类型',
              }"
          >
            <a-select v-model="listenerForm.scriptType">
              <a-select-option value="inlineScript">
                内联脚本
              </a-select-option>
              <a-select-option value="externalScript">
                外部脚本
              </a-select-option>
            </a-select>
          </a-form-model-item>
          <a-form-model-item
              v-if="listenerForm.scriptType === 'inlineScript'"
              key="listener-script"
              label="脚本内容"
              prop="value"
              :rules="{
                required: true,
                trigger: ['blur', 'change'],
                message: '请填写脚本内容',
              }"
          >
            <a-input
                v-model="listenerForm.value"
                allow-clear
            />
          </a-form-model-item>
          <a-form-model-item
              v-if="listenerForm.scriptType === 'externalScript'"
              key="listener-resource"
              label="资源地址"
              prop="resource"
              :rules="{
                required: true,
                trigger: ['blur', 'change'],
                message: '请填写资源地址',
              }"
          >
            <a-input
                v-model="listenerForm.resource"
                allow-clear
            />
          </a-form-model-item>
        </template>
      </a-form-model>
      <a-divider />
      <a-card
          title="注入字段："
          :bordered="false"
          size="small"
      >
        <span
            slot="extra"
        ><a-button
            size="small"
            style="float: right"
            type="primary"
            @click="openListenerFieldForm(null)"
        >添加字段</a-button></span>
        <a-table
            row-key="index"
            :data-source="fieldsListOfListener"
            :scroll="{ x: 500 }"
            size="small"
            bordered
            :pagination="false"
        >
          <a-table-column
              title="序号"
              data-index="index"
              width="50px"
              :custom-render="(text, record, index) => `${index + 1}`"
          />
          <a-table-column
              title="字段名称"
              data-index="name"
              width="100px"
          />
          <a-table-column
              title="字段类型"
              width="80px"
              :custom-render="(row) => fieldTypeObject[row.fieldType]"
          />
          <a-table-column
              title="字段值/表达式"
              :custom-render="
                (row) =>
                  row.fieldType === 'string' ? row.string : row.expression
              "
          />
          <a-table-column
              title="操作"
              width="100px"
              fixed="right"
          >
            <template slot-scope="text, record, index">
              <a-button
                  size="small"
                  type="link"
                  @click="openListenerFieldForm(record, index)"
              >
                编辑
              </a-button>
              <a-divider type="vertical" />
              <a-button
                  size="small"
                  type="link"
                  style="color: #ff4d4f"
                  @click="removeListenerField(record, index)"
              >
                移除
              </a-button>
            </template>
          </a-table-column>
        </a-table>
      </a-card>

      <div
          :style="{
            position: 'absolute',
            right: 0,
            bottom: 0,
            width: '100%',
            borderTop: '1px solid #e9e9e9',
            padding: '10px 16px',
            background: '#fff',
            textAlign: 'right',
            zIndex: 1,
          }"
      >
        <a-button
            :style="{ marginRight: '8px' }"
            @click="listenerFormModelVisible = false"
        >
          取 消
        </a-button>
        <a-button
            type="primary"
            @click="saveListenerConfig"
        >
          保 存
        </a-button>
      </div>
    </a-drawer>

    <!-- 注入西段 编辑/创建 部分 -->
    <a-modal
        title="字段配置"
        :visible="listenerFieldFormModelVisible"
        width="600px"
        destroy-on-close
        @close="listenerFieldFormModelVisible = false"
    >
      <a-form-model
          ref="listenerFieldFormRef"
          :model="listenerFieldForm"
          :label-col="{ span: 6 }"
          :wrapper-col="{ span: 18 }"
      >
        <a-form-model-item
            label="字段名称："
            prop="name"
            :rules="{ required: true, trigger: ['blur', 'change'] }"
        >
          <a-input
              v-model="listenerFieldForm.name"
              allow-clear
          />
        </a-form-model-item>
        <a-form-model-item
            label="字段类型："
            prop="fieldType"
            :rules="{ required: true, trigger: ['blur', 'change'] }"
        >
          <a-select v-model="listenerFieldForm.fieldType">
            <a-select-option
                v-for="(value, key, index) in fieldTypeObject"
                :key="key"
                :value="key"
            >
              {{ value }}
            </a-select-option>
          </a-select>
        </a-form-model-item>
        <a-form-model-item
            v-if="listenerFieldForm.fieldType === 'string'"
            key="field-string"
            label="字段值："
            prop="string"
            :rules="{ required: true, trigger: ['blur', 'change'] }"
        >
          <a-input
              v-model="listenerFieldForm.string"
              allow-clear
          />
        </a-form-model-item>
        <a-form-model-item
            v-if="listenerFieldForm.fieldType === 'expression'"
            key="field-expression"
            label="表达式："
            prop="expression"
            :rules="{ required: true, trigger: ['blur', 'change'] }"
        >
          <a-input
              v-model="listenerFieldForm.expression"
              allow-clear
          />
        </a-form-model-item>
      </a-form-model>
      <template slot="footer">
        <a-button
            size="small"
            @click="listenerFieldFormModelVisible = false"
        >
          取 消
        </a-button>
        <a-button
            size="small"
            type="primary"
            @click="saveListenerFiled"
        >
          确 定
        </a-button>
      </template>
    </a-modal>
  </div>
</template>
<script>
export default {
  name: 'Listeners',
  inject: {
    prefix: 'prefix',
    width: 'width'
  },
  props: {
    id: String,
    type: String
  },
  data() {
    return {
      listenersList: [], // 监听器列表
      listenerForm: {}, // 监听器详情表单
      listenerFormModelVisible: false, // 监听器 编辑 侧边栏显示状态
      fieldsListOfListener: [],
      listenerFieldForm: {}, // 监听器 注入字段 详情表单
      listenerFieldFormModelVisible: false, // 监听器 注入字段表单弹窗 显示状态
      editingListenerIndex: -1, // 监听器所在下标，-1 为新增
      editingListenerFieldIndex: -1, // 字段所在下标，-1 为新增
      listenerTypeObject: {
        classListener: 'Java 类',
        expressionListener: '表达式',
        delegateExpressionListener: '代理表达式',
        scriptListener: '脚本'
      },
      fieldTypeObject: {
        string: '字符串',
        expression: '表达式'
      }
    }
  },
  watch: {
    id: {
      immediate: true,
      handler(val) {
        val && val.length && this.$nextTick(() => this.resetListenersList())
      }
    }
  },
  methods: {
    resetListenersList() {
      this.bpmnElement = window.bpmnInstances.bpmnElement
      this.otherExtensionList = []
      this.bpmnElementListeners =
        this.bpmnElement.businessObject?.extensionElements?.values?.filter(
          (ex) => {
            if (ex.$type !== `${this.prefix}:ExecutionListener`) {
              this.otherExtensionList.push(ex)
            }
            return ex.$type === `${this.prefix}:ExecutionListener`
          }
        ) ?? []
      this.elementListenersList = this.bpmnElementListeners.map((listener) => {
        let listenerType
        if (listener.class) listenerType = 'classListener'
        if (listener.expression) listenerType = 'expressionListener'
        if (listener.delegateExpression) { listenerType = 'delegateExpressionListener' }
        if (listener.script) listenerType = 'scriptListener'
        return {
          ...JSON.parse(JSON.stringify(listener)),
          ...(listener.script ?? {}),
          listenerType: listenerType
        }
      })
    },
    // 打开 监听器详情 侧边栏
    openListenerForm(listener, index) {
      if (listener) {
        if (listener.script) {
          this.listenerForm = {
            ...listener,
            ...listener.script,
            scriptType: listener.script.resource
              ? 'externalScript'
              : 'inlineScript'
          }
        } else {
          this.listenerForm = { ...listener }
        }
        this.editingListenerIndex = index
      } else {
        this.listenerForm = {}
        this.editingListenerIndex = -1 // 标记为新增
      }
      if (listener && listener.fields) {
        this.fieldsListOfListener = listener.fields.map((field) => ({
          ...field,
          fieldType: field.string ? 'string' : 'expression'
        }))
      } else {
        this.fieldsListOfListener = []
        this.$set(this.listenerForm, 'fields', [])
      }
      // 打开侧边栏并清楚验证状态
      this.listenerFormModelVisible = true
      this.$nextTick(() => {
        if (this.$refs['listenerFormRef']) { this.$refs['listenerFormRef'].clearValidate() }
      })
    },
    // 打开监听器字段编辑弹窗
    openListenerFieldForm(field, index) {
      this.listenerFieldForm = field ? JSON.parse(JSON.stringify(field)) : {}
      this.editingListenerFieldIndex = field ? index : -1
      this.listenerFieldFormModelVisible = true
      this.$nextTick(() => {
        if (this.$refs['listenerFieldFormRef']) { this.$refs['listenerFieldFormRef'].clearValidate() }
      })
    },
    // 保存监听器注入字段
    async saveListenerFiled() {
      const validateStatus = await this.$refs[
        'listenerFieldFormRef'
      ].validate()
      if (!validateStatus) return // 验证不通过直接返回
      if (this.editingListenerFieldIndex === -1) {
        this.fieldsListOfListener.push(this.listenerFieldForm)
        this.listenerForm.fields.push(this.listenerFieldForm)
      } else {
        this.fieldsListOfListener.splice(
          this.editingListenerFieldIndex,
          1,
          this.listenerFieldForm
        )
        this.listenerForm.fields.splice(
          this.editingListenerFieldIndex,
          1,
          this.listenerFieldForm
        )
      }
      this.listenerFieldFormModelVisible = false
      this.$nextTick(() => (this.listenerFieldForm = {}))
    },
    // 移除监听器字段
    removeListenerField(field, index) {
      const that = this
      this.$confirm({
        title: '提示',
        content: '确认移除该字段吗？',
        onOk() {
          that.fieldsListOfListener.splice(index, 1)
          that.listenerForm.fields.splice(index, 1)
        }
      })
    },
    // 移除监听器
    removeListener(listener, index) {
      const that = this
      this.$confirm({
        title: '提示',
        content: '确认移除该字段吗？',
        onOk() {
          that.bpmnElementListeners.splice(index, 1)
          that.listenersList.splice(index, 1)
          that.updateElementExtensions()
        }
      })
    },
    // 保存监听器配置
    async saveListenerConfig() {
      const validateStatus = await this.$refs['listenerFormRef'].validate()
      if (!validateStatus) return // 验证不通过直接返回
      const listenerObject = window.bpmnInstances.moddle.create(
        `${this.prefix}:ExecutionListener`,
        this.initListenerObject(this.listenerForm)
      )
      if (this.editingListenerIndex === -1) {
        this.bpmnElementListeners.push(listenerObject)
        this.listenersList.push(this.listenerForm)
      } else {
        this.bpmnElementListeners.splice(
          this.editingListenerIndex,
          1,
          listenerObject
        )
        this.listenersList.splice(
          this.editingListenerIndex,
          1,
          this.listenerForm
        )
      }
      this.updateElementExtensions()
      // 4. 隐藏侧边栏
      this.listenerFormModelVisible = false
      this.listenerForm = {}
    },
    // 创建监听器实例
    initListenerObject(options) {
      const listenerObj = Object.create(null)
      listenerObj.event = options.event
      switch (options.listenerType) {
        case 'scriptListener':
          listenerObj.script = this.initScriptObject()
          break
        case 'expressionListener':
          listenerObj.expression = options.expression
          break
        case 'delegateExpressionListener':
          listenerObj.delegateExpression = options.delegateExpression
          break
        default:
          listenerObj.class = options.class
      }
      if (options.fields) {
        listenerObj.fields = options.fields.map((field) => {
          return this.initFieldObject(field)
        })
      }
      return listenerObj
    },
    // 创建 脚本 实例
    initScriptObject() {
      const { scriptType, scriptFormat, value, resource } = this.listenerForm
      const scriptConfig =
        scriptType === 'inlineScript'
          ? { scriptFormat, value }
          : { scriptFormat, resource }
      return window.bpmnInstances.moddle.create(
        `${this.prefix}:Script`,
        scriptConfig
      )
    },
    // 创建 字段 实例
    initFieldObject(option) {
      const { name, fieldType, string, expression } = option
      const fieldConfig =
        fieldType === 'string' ? { name, string } : { name, expression }
      return window.bpmnInstances.moddle.create(
        `${this.prefix}:Field`,
        fieldConfig
      )
    },
    // 更新元素扩展属性
    updateElementExtensions() {
      const extensions = window.bpmnInstances.moddle.create(
        'bpmn:ExtensionElements',
        {
          values: this.otherExtensionList.concat(this.bpmnElementListeners)
        }
      )
      window.bpmnInstances.modeling.updateProperties(this.bpmnElement, {
        extensionElements: extensions
      })
    }
  }
}
</script>
